const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  address: {
    type: String,
    required: false,
    unique: true,
    sparse: true,
    lowercase: true,
    match: [/^0x[a-fA-F0-9]{40}$/, 'Invalid Ethereum address format']
  },
  username: {
    type: String,
    required: true,
    trim: true,
    minlength: 2,
    maxlength: 50
  },
  email: {
    type: String,
    required: true,
    unique: true,
    lowercase: true,
    match: [/^\S+@\S+\.\S+$/, 'Invalid email format']
  },
  password: {
    type: String,
    required: true,
    minlength: 6
  },
  phone: {
    type: String,
    match: [/^[\+]?[1-9][\d]{0,15}$/, 'Invalid phone number']
  },
  role: {
    type: String,
    required: true,
    enum: ['farmer', 'logistics', 'merchant', 'consumer', 'admin'],
    default: 'consumer'
  },
  profile: {
    name: {
      type: String,
      trim: true,
      maxlength: 100
    },
    avatar: {
      type: String,
      match: [/^https?:\/\/.+/, 'Invalid avatar URL']
    },
    description: {
      type: String,
      maxlength: 500
    },
    location: {
      type: String,
      maxlength: 200
    },
    certifications: [{
      type: String,
      match: [/^https?:\/\/.+/, 'Invalid certification URL']
    }]
  },
  status: {
    type: String,
    enum: ['active', 'inactive', 'suspended', 'deleted'],
    default: 'active'
  },
  deletedAt: Date,
  emailVerified: {
    type: Boolean,
    default: false
  },
  emailVerificationToken: String,
  passwordResetToken: String,
  passwordResetExpires: Date,
  refreshTokens: [{
    token: String,
    expiresAt: Date,
    createdAt: {
      type: Date,
      default: Date.now
    }
  }],
  lastLoginAt: Date,
  loginAttempts: {
    type: Number,
    default: 0
  },
  accountLockedUntil: Date,
  lastFailedLogin: Date
}, {
  timestamps: true,
  toJSON: {
    transform: function(doc, ret) {
      delete ret.password;
      delete ret.refreshTokens;
      delete ret.emailVerificationToken;
      delete ret.passwordResetToken;
      delete ret.passwordResetExpires;
      delete ret.loginAttempts;
      return ret;
    }
  }
});

// 索引 - email和address已在字段定义中设置unique，无需重复定义
userSchema.index({ role: 1 }, { name: 'idx_user_role' });
userSchema.index({ status: 1 }, { name: 'idx_user_status' });
userSchema.index({ role: 1, status: 1 }, { name: 'idx_user_role_status' });

// 密码加密中间件
userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  
  try {
    const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS) || 12;
    this.password = await bcrypt.hash(this.password, saltRounds);
    next();
  } catch (error) {
    next(error);
  }
});

// 比较密码方法
userSchema.methods.comparePassword = async function(candidatePassword) {
  return bcrypt.compare(candidatePassword, this.password);
};

// 更新最后登录时间
userSchema.methods.updateLastLogin = function() {
  this.lastLoginAt = new Date();
  this.loginAttempts = 0;
  this.accountLockedUntil = undefined;
  this.lastFailedLogin = undefined;
  return this;
};

// 检查账户是否被锁定
userSchema.methods.isAccountLocked = function() {
  return !!(this.accountLockedUntil && this.accountLockedUntil > new Date());
};

// 添加刷新令牌
userSchema.methods.addRefreshToken = function(token) {
  this.refreshTokens.push({ token });
  
  // 保持最多5个刷新令牌
  if (this.refreshTokens.length > 5) {
    this.refreshTokens = this.refreshTokens.slice(-5);
  }
  
  return this.save();
};

// 移除刷新令牌
userSchema.methods.removeRefreshToken = function(token) {
  this.refreshTokens = this.refreshTokens.filter(
    refreshToken => refreshToken.token !== token
  );
  return this.save();
};

// 清除所有刷新令牌
userSchema.methods.clearRefreshTokens = function() {
  this.refreshTokens = [];
  return this.save();
};

// 静态方法：根据邮箱查找用户
userSchema.statics.findByEmail = function(email) {
  return this.findOne({ email: email.toLowerCase() });
};

// 静态方法：根据地址查找用户
userSchema.statics.findByAddress = function(address) {
  return this.findOne({ address: address.toLowerCase() });
};

// 静态方法：根据角色查找用户
userSchema.statics.findByRole = function(role) {
  return this.find({ role, status: 'active' });
};

module.exports = mongoose.model('User', userSchema);